package com.ude.pim.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ude.pim.common.R;
import com.ude.pim.dto.CaseDTO;
import com.ude.pim.dto.CaseQueryDTO;
import com.ude.pim.entity.Case;
import com.ude.pim.entity.CaseSub;
import com.ude.pim.entity.Sub;
import com.ude.pim.entity.User;
import com.ude.pim.mapper.CaseMapper;
import com.ude.pim.service.CaseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ude.pim.service.CaseSubService;
import com.ude.pim.service.SubService;
import com.ude.pim.service.UserService;
import com.ude.pim.utils.PIMConstants;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.ude.pim.utils.PIMConstants.CASE_LIST;

/**
 * <p>
 * 专案表	记录专案的信息，包括：	id	名称	难度	专案号	负责人	创建时间	创建人	预计完成时间	实际完成时间	状态 服务实现类
 * </p>
 *
 * @author yb
 * @since 2023-08-08
 */
@Service
@Transactional
public class CaseServiceImpl extends ServiceImpl<CaseMapper, Case> implements CaseService {
    @Autowired
    private UserService userService;

    @Autowired
    private CaseSubService caseSubService;

    @Autowired
    private SubService subService;


    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 1. 按名称查询
     * 2. 按难度查询
     * 3. 按负责人查询
     * 4. 在指定时间之后开始
     * 5. 在指定时间之前完结
     *
     * @param caseQueryDTO
     * @return
     */
    @Override
    public R<List<Case>> page(CaseQueryDTO caseQueryDTO) {
        LambdaQueryWrapper<Case> lqw = new LambdaQueryWrapper<>();
        // 1. 按名称查询
        String name = caseQueryDTO.getName();
        if (StringUtils.isNotEmpty(name))
            lqw.like(Case::getName, name);

        // 2. 按难度查询
        Integer level = caseQueryDTO.getLevel();
        if (level != null)
            lqw.eq(Case::getLevel, level);

        // 3. 按负责人查询
        String chargeName = caseQueryDTO.getChargeName();
        User one = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getName, chargeName));
        if (one != null)
            lqw.eq(Case::getDirector, one.getId());



        return R.success(this.list(lqw));
    }

    /**
     * 1. 删除子流程相关的评论
     * 2. 删除子流程相关的问题
     * 3. 删除子流程相关的负责人
     * 4. 删除相关的子流程
     *
     * @param caseId
     * @return
     */
    @Override
    public R<String> delete(Long caseId) {
        //todo 完成注释上面的功能后再来写该功能
        List<CaseSub> list = caseSubService.list(new LambdaQueryWrapper<CaseSub>().eq(CaseSub::getCaseId, caseId));
        list.forEach(s -> caseSubService.removeById(s.getId()));
        this.removeById(caseId);
        return R.success("删除成功");
    }

    @Override
    public R<List<CaseDTO>> getlist() {
        String key="case:list";
        //查询缓存
        String caseJSON = stringRedisTemplate.opsForValue().get(key);
        if(StringUtils.isNotBlank(caseJSON)){
            List<CaseDTO> caseDTOS = JSONUtil.toList(caseJSON, CaseDTO.class);
            return R.success(caseDTOS);
        }

        //没有缓存则重建缓存

        List<Case> list = this.list();
        List<CaseDTO> dtoList = list.stream()
                //过滤空专案
                .filter(s-> caseSubService.list(new LambdaQueryWrapper<CaseSub>().eq(CaseSub::getCaseId, s.getId()).orderByDesc(CaseSub::getSubId)).size()!=0)
                .map(s -> {
            CaseDTO caseDTO = new CaseDTO();
            BeanUtils.copyProperties(s, caseDTO);
            //按照专案id查询子流程列表，并按照子流程序号降序排列
            List<CaseSub> subs = caseSubService.list(new LambdaQueryWrapper<CaseSub>().eq(CaseSub::getCaseId, s.getId()).orderByDesc(CaseSub::getSubId));
            //原子类，计算外界因素延期
            AtomicReference<Integer> unforcedDay = new AtomicReference<>(0);
            //原子类，计算计划天数
            AtomicReference<Integer> planDay = new AtomicReference<>(0);
            //当前专案进度
            AtomicReference<String> curStage = new AtomicReference<>();

            //最后一个子阶段的完结时间（降序，所以是第一个）
            LocalDateTime finishTime = subs.get(0).getFinishTime();
            if (finishTime != null)
                caseDTO.setFinishTime(finishTime);

            //开始时间，第一个子阶段的开始时间，所以是最后一个
            LocalDateTime startTime = subs.get(subs.size() - 1).getStartTime();
            if(startTime!=null)
                caseDTO.setStartTime(startTime);


            subs.forEach(k -> {
                //按照子流程降序排列，最后一个结束时间为空的子流程就是当前专案进度
                if (k.getFinishTime() == null) {
                    curStage.set(subService.getOne(new LambdaQueryWrapper<Sub>().eq(Sub::getId, k.getSubId())).getName());
                }
                //外界因素延期总和
                if (k.getUnforcedDays() != null)
                    unforcedDay.updateAndGet(v -> v + k.getUnforcedDays());
                //计划天数总和
                if (k.getPlanDays() != null)
                    planDay.updateAndGet(v -> v + k.getPlanDays());
            });
            caseDTO.setUnforcedDay(unforcedDay.get());
            caseDTO.setPlanDay(planDay.get());
            caseDTO.setCurStage(curStage.get());
            return caseDTO;

        }).collect(Collectors.toList());

        //写入redis（2小时后过期）
        stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(dtoList), PIMConstants.NORMAL_TTL, TimeUnit.HOURS);

        return R.success(dtoList);
    }

    @Override
    public R<String> getNameById(Long id) {
        Case caseObject = this.getById(id);
        return R.success(caseObject.getName());
    }

    /**
     * 1. 判断专案名称是否有重复
     * @param c
     * @return
     * @throws Exception
     */
    @Override
    public R<String> saveCase(Case c) throws Exception {
        String name = c.getName();
        LambdaQueryWrapper<Case> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Case::getName,name);
        List<Case> list = this.list(lqw);
        if(list.size()!=0){
            return R.error("专案名已存在，请重新输入");
        }
        c.setCreateTime(LocalDateTime.now());
        this.save(c);
        return R.success("新建专案成功");
    }

}
